#ifndef XL_OBSERVABLE_H
#define XL_OBSERVABLE_H
#include <assert.h>
#include <vector>
#include <windows.h>

template <class T>
class CObserableT
{
protected:
	typedef unsigned int                        EVT;

public:
	class IObserver
	{
	public:
		typedef typename CObserableT::EVT   EVT;
		virtual void onEvent(
		                     EVT evt,
		                     void *param
		                    ) = 0;
	};

protected:
	typedef std::vector<IObserver *>            _Subscribers;
	typedef typename _Subscribers::iterator     _Iter;
	_Subscribers         m_subscribers;

	CRITICAL_SECTION     m_cs;
	void _Lock() {::EnterCriticalSection(&m_cs);}
	void _Unlock() {::LeaveCriticalSection(&m_cs);}

	void _TriggerEvent(EVT evt, void *param) {
		assert (evt < T::EVT_NUM);
		_Lock();
		for (_Iter it = m_subscribers.begin(); it != m_subscribers.end(); ++ it) {
			(*it)->onEvent(evt, param);
		}
		_Unlock();
	}

	// before call it, _Lock() should already be called
	_Iter _FindSubscriber(IObserver *observer) {
		_Iter it;
		for (it = m_subscribers.begin(); it != m_subscribers.end(); ++ it) {
			if (*it == observer) {
				break;
			}
		}
		return it;
	}

public:
	CObserableT() {
		::InitializeCriticalSection(&m_cs);
	}

	virtual ~CObserableT() {
		::DeleteCriticalSection(&m_cs);
	}

	void subscribe(IObserver *subscriber, bool asTail = true) {
		assert (subscriber != NULL);

		_Lock();
		assert (_FindSubscriber(subscriber) == m_subscribers.end());
		m_subscribers.insert(asTail ? m_subscribers.end() : m_subscribers.begin(), subscriber);
		_Unlock();
	}

	void unsubscribe(IObserver *observer) {
		assert (observer != NULL);

		_Lock();
		_Iter it = _FindSubscriber(observer);
		assert (it != m_subscribers.end());
		m_subscribers.erase(it);
		_Unlock();
	}
};

#endif
